#include <stdio.h>
#include <math.h>
#include <gmp.h>
#include <sys/time.h>
#include <time.h>
#include <pthread.h>

struct timeval inicio, final;
pthread_t thread1, thread2;
mpf_t a, y, an, ny, temp;
unsigned long int twoexp = 8;

// a*(1+ny)^4 no calculo de an
void *leftA() {
	mpf_add_ui(temp, ny, 1);
	mpf_pow_ui(temp, temp, 4);
	mpf_mul(temp, a, temp);
	pthread_exit(NULL);
}

// 2^(2*i+3)*ny*(1+ny+ny^2)	no calculo de an
void *rightA() {
	mpf_pow_ui(an, ny, 2);
	mpf_add(an, ny, an);
	mpf_add_ui(an, an, 1);
	mpf_mul(an, ny, an);
	mpf_mul_ui(an, an, twoexp);
	pthread_exit(NULL);
}

int main() {
	gettimeofday(&inicio, NULL);
	
	// O arquivo se chamara "BorweinP" na mesma pasta do arquivo .c
	int i = 0, time;
	FILE *file;
    file = fopen("BorweinP", "w+");
		
	mpf_set_default_prec(33219280);

	// Inicializacao
	mpf_init(a);
	mpf_init(y);
	mpf_init(an);
	mpf_init(ny);
	mpf_init(temp);
	
	// Calculo de a0 e y0
	mpf_sqrt_ui(y, 2);
	mpf_mul_ui(a, y, 4);
	mpf_sub_ui(y, y, 1);
	mpf_ui_sub(a, 6, a);
	
	while(1) {
		printf("Iter n. %d\n", ++i);

		// ny = (1-(1-y^4)^(1/4))/(1+(1-y^4)^(1/4))
		mpf_pow_ui(y, y, 4);
		mpf_ui_sub(y, 1, y);
		mpf_sqrt(y, y);
		mpf_sqrt(y, y);
		mpf_add_ui(temp, y, 1);
		mpf_ui_sub(y, 1, y);
		mpf_div(ny, y, temp);
		
		// an = a*(1+ny)^4-2^(2*i+3)*ny*(1+ny+ny^2)		
		// Cria as duas threads
		pthread_create(&thread1, NULL, leftA, NULL);
		pthread_create(&thread2, NULL, rightA, NULL);
		pthread_join(thread1, NULL);
		pthread_join(thread2, NULL);
		mpf_sub(an, temp, an);
		
		// Calcula o pi anteirior
		mpf_ui_div(temp, 1, a);
		// Atualiza anteriores
		mpf_set(a, an);
		mpf_set(y, ny);
		// Atualiza fator 2^(k*2+3)
		twoexp *= 4;
		
		// Calcula novo pi
		mpf_ui_div(an, 1, an);
		
		// Se nao houve mudanca no pi, escreve no arquivo
		if(mpf_cmp(temp, an) >= 0) {
			size_t writtenBytes = mpf_out_str(file, 10, 0, an);
			break;
		}		
	}
	// Finalizacao
	close(file);
	mpf_clear(a);
	mpf_clear(y);
	mpf_clear(an);
	mpf_clear(ny);
	mpf_clear(temp);

	// Calculo do tempo decorrido
	gettimeofday(&final, NULL);
	time = final.tv_sec - inicio.tv_sec;
	printf("Tempo: %i segundos.\n", time);
	return 0;
}
